Skip to main content

Gamepad Controls

In the driver-controlled period of the FTC match your drivers use controllers to drive and control robots

Controllers

Currently, there are four controllers legal for FTC use.

caution

Even though the Dual Shock 4 Controller has wireless capabilities, a USB must be used connect it to the driver station. Wireless controller connections are not allowed for FTC.

What Controller Should I Use?

The usual consensus for the best controller available is the Dual Shock 4. The joysticks, triggers, and buttons feel better than the ones on other controller, as well as the fact that it has a touchpad. It also provides haptic feedback with the ability to vibrate to tell your drivers something, however this controller also comes with the highest price tag. If looking for a cost effective option, our team recommends the Logitech F310 controller as it is found at most stores for $20, and it is a reliable controller.'

Gamepad Controls

The gamepad has two main types of input. A Boolean output that returns either true or false depending on if the button is the pressed or not. The other type is a double output returning a 0-1 double.

Boolean Outputs

  • Buttons A, X, Y, B
  • D-pad Buttons
  • Left and Right Bumpers
  • Misc Buttons(Share, Options, Start, Touchpad)

Double Outputs

  • Left and Right Triggers
  • Both Joysticks

Assigning Gamepad Controls

When referencing a gamepad in the code, you can use either gamepad1 or gamepad2 which refers to either the Driver 1 or Driver 2 controller. This will be followed by the button that you are trying to assign a command to.

gamepad1.a                  //a button on Driver 1 Controller
gamepad2.dpad_up //dpad up on Driver 2 Controller

gamepad1.left_stick_x; //0-1 value based on left horizontal joystick movement
gamepad1.left_trigger; //0-1 value based on trigger position
info

When using the y value for joysticks, moving the joystick down will return a positive value and moving it up will return negative. If you wish to switch it simply multiply the returned value by -1.

Assigning a Button to a Task

Here is some basic code to move a servo to different positions depending on when a button is it. Assume a servo has already been initialized.

if(gamepad1.a){
servo.setPosition(0.5); //Task if a is pressed
}else if(gamepad1.b){
servo.setPosition(1); //Task if b is pressed
}

Using a Double Output

There are two ways that you can use a double output, assigning the output as a power to a motor, or using it just like a button by making it return true or false.

Assigning Double Output to a Motor

One of the most common uses for the triggers and the joysticks is to assign the value outputted by them to a motor. The more pressed down or moved it is the higher power will be outputted by the motor. In this example, assume the motors sweeper and flywheel have already been instantiated.

double sweeperPower = gamepad1.right_trigger;
double flywheelPower = gamepad1.left_stick_y * -1;

sweeper.setPower(sweeperPower);
flywheel.setPower(flywheelPower);

As shown in this example, the right trigger value is assigned to the sweeper motor and the left joystick y axis value is assigned to the trigger motor. Remember, the y axis of a joystick initially returns a negative number going up, so to change that the power is multiplied by negative 1.

info

To explain a little more about how the joystick is programmed with the gamepad, there are two joysticks on each gamepad, you reference which one you want to use by using left_stick or right_stick. Each joystick also has two axis, an x-axis, left and right movement, and a y-axis, up and down movement. Therefore, there are four different joystick values that can be obtained on each gamepad. This will be important when programming your drive train.

Using a Trigger/Joystick as a Button

In some cases, you might have used up all buttons on your gamepad and just want to use a trigger or joystick as a button to initiate another action. The solution is simple, create a boolean checking if the value outputted is larger then a small double value, and if so the "button" is being pressed.

boolean isPressed;

isPressed = gamepad1.right_trigger > 0.1;

if(isPressed){
//Task to Complete
}

Detecting Button Presses

The Wrong Way

Now, in many cases, it is simpler for the driver to use the same button for different tasks regarding the same module. For example, toggling the positions of a servo, or turning a motor on and off. Your first idea for how to do this would look something like this. Assume servo is initialized.

boolean downPosition = true; //alternating between down and up

if(gamepad1.a){
downPosition = !downPosition; //switches position
if(downPosition){
servo.setPosition(0); //Moving down
}else{
servo.setPosition(1); //Moving up
}
}

This logic says that if 'a' has been pressed, to change the value of the downPosition boolean. If it has been changed to true, the servo should move to the down position, if it has been changed to false, the servo should be moved up.

Why Wouldn't this Work?

The logic may seem right but there is a reason this wouldn't work. As you know, FTC tele-op's run in loops. These loops keep looping at rapid speeds, one loop only takes a few milliseconds. Therefore, if you press the 'a' button the program will loop many times while you are still pressing it, causing the servo to try to move up then immediately down, and so on as the program keeps looping. All this will do is result in a servo that jitters when you press 'a'.

The Right Way

boolean lastMovement = false, currMovement = false;
boolean downPosition = true;

lastMovement = currMovement;
currMovement = gamepad1.a;

if(currMovement && !lastMovement){
downPosition = !downPosition;
if(downPosition){
servo.setPosition(0); //Move Down
}else{
servo.setPosition(1); //Move Up
}
}

This may seem confusing, but there is a logical explanation behind this code. Here we are setting up two booleans lastMovement and currMovement. We set lastMovement equal to currMovement, and afterward, we set currMovement to the boolean gamepad1.a.

Now, we only enter the if statement to switch the servo position if currMovement is true and lastMovement is false. The first loop when 'a' is pressed will result in the lastMovement = currMovement line having both booleans at false.

However, the next line will change currMovement to true, this will allow the servo position to change. However, on the next loop, since the button is still being pressed, in the next loop, the lastMovement = currMovement line will set lastMovement to true, leading to both currMovement and lastMovement being true, meaning the statement will not be executed. Therefore, this code will ensure that an action will only occur once for each press of a button.